#ifndef __LISTCPP__
#define __LISTCPP__
#include <iostream>
#include "List.h"

template<class T>
class ListCpp
{
    public:

        class LIter;
        class CLIter;

        ListCpp(); // default ctor- make empty list
        ~ListCpp();//Default dtor
        ListCpp(const ListCpp& other);//Copy ctor
        ListCpp& operator=(const ListCpp& other); // Assignment operator
        bool     IsEmpty()const;// return true if list is empty ,else false

        /**funcs that workes with const iterator**/
        CLIter  Begin()const;//return const iterator to first element
        CLIter  End()const;//return const iterator to the past-the-end element

        // insert before target of const iterator,return iterator to data
        // if iterator target is not a data node or the End(),behavior is undefined
        LIter   Insert(CLIter _it,T* _data);
        LIter   Remove(CLIter _it); // Remove iterator _it, return next iterator after the romved one

        /**funcs that workes with iterator**/
        LIter   Begin();//return iterator to first element
        LIter   End();//return iterator to the past-the-end element

        // insert before target of iterator,return iterator to data
        // if iterator target is not a data node or the End(),behavior is undefined
        LIter   Insert(LIter _it,T* _data);
        LIter   Remove(LIter _it);// Remove iterator _it, return next iterator after the romved one

    private:

        List* m_list;//c List
};

template<class T>
class ListCpp<T>::LIter
{
    public:

        //LIter();                        default CTOR forbidden
        //~LIter();                       DTOR provided by compiler
        //LIter(const LIter&)             copy CTOR provided by compiler
        //LIter& operator=(const LIter&)  assignment operator provided by compiler

        LIter& operator++();//step to next data node
        LIter& operator--();//step to previous data node
        T*     Get() const  ;      //return pointer to data in iterator's target

        friend LIter ListCpp<T>::Begin();
        friend LIter ListCpp<T>::End();
        friend LIter ListCpp<T>::Insert(LIter _it,T* _data);
        friend LIter ListCpp<T>::Remove(LIter _it);
        friend LIter ListCpp<T>::Remove(CLIter _it);

        bool operator==(const CLIter& _iter);
        bool operator!=(const CLIter& _iter);

    private :

        LIter(const ListIter& _cListIter);//ctor from List c iter ,for use of class ListCpp

        #ifdef _DEBUG//in debug mode we chek if iterator is legal
            LIter(const ListIter& _cListIter,List* _cList);
            List* m_list;//list of the iterator
        #endif //_DEBUG

        ListIter m_iter;//c list iterator

    protected:
        const ListIter& GetIter()const;
};


template<class T>
class ListCpp<T>::CLIter :  private ListCpp<T>::LIter
{
    public:

        //CLIter();                            default CTOR forbidden
        //~CLIter();                           DTOR provided by compiler
        //CLIter(const CLIter&)             copy CTOR provided by compiler
        //CLIter& operator=(const CLIter&)  assignment operator provided by compiler

        using ListCpp<T>::LIter::operator++; //step to next data node
        using ListCpp<T>::LIter::operator--;//step to previous data node
        const T*    Get()const ;// return pointer to data in iterator's target

        CLIter(const ListCpp::LIter& _liter);// implicit conversion to const iterator

        bool operator==(const CLIter& _iter)const;
        bool operator!=(const CLIter& _iter)const;

    private:
        using ListCpp<T>::LIter::GetIter;
};


/******************************************************************************/
/**                     implementation of class Iter                         **/
/******************************************************************************/
template<class T>
ListCpp<T>::LIter::LIter(const ListIter& _cListIter):m_iter(_cListIter){}

#ifdef _DEBUG//in debug mode we chek if iterator is legal
    template<class T>
    ListCpp<T>::LIter::LIter(const ListIter& _cListIter,List* _cList):m_iter(_cListIter),m_list(_cList){}
#endif //_DEBUG

template<class T>
typename ListCpp<T>::LIter&   ListCpp<T>::LIter::operator++()
{
    //todo chekout of iterators in debug mode
    m_iter = ListIterNext(m_iter);
    return *this;
}

template<class T>
typename ListCpp<T>::LIter&   ListCpp<T>::LIter::operator--()
{
    //todo chekout of iterators in debug mode
    m_iter = ListIterPrev(m_iter);
    return *this;
}

template<class T>
T*  ListCpp<T>::LIter::Get() const
{
    return  reinterpret_cast<T*>((ListGetData(m_iter)));
}

template<class T>
bool ListCpp<T>::LIter::operator==(const CLIter& _iter)
{
   return _iter.operator==(*this);
}

template<class T>
bool ListCpp<T>::LIter::operator!=(const CLIter& _iter)
{
    return _iter.operator!=(*this);
}

template<class T>
const ListIter& ListCpp<T>::LIter::GetIter()const
{
    return m_iter;
}

/******************************************************************************/
/**                     implementation of class CIter                        **/
/******************************************************************************/

template<class T>
const T*  ListCpp<T>::CLIter::Get()const
{
   return static_cast<const T*>( LIter::Get() );
}

template<class T>
ListCpp<T>::CLIter::CLIter(const ListCpp<T>::LIter& _liter):ListCpp<T>::LIter::LIter(_liter){}

template<class T>
bool ListCpp<T>::CLIter::operator==(const CLIter& _iter)const
{
    return ListIterIsEqual(GetIter(),_iter.GetIter());
}

template<class T>
bool ListCpp<T>::CLIter::operator!=(const CLIter& _iter)const
{
    return !operator==(_iter);
}

/******************************************************************************/
/**                     implementation of class ListCpp                      **/
/******************************************************************************/
template<class T>
ListCpp<T>::ListCpp()
{
    m_list = ListNew();
}

template<class T>
ListCpp<T>::~ListCpp()
{
   listDestroy(m_list);
}

template<class T>
typename ListCpp<T>::LIter ListCpp<T>::Begin()
{
    LIter   it(ListBegin(m_list));
    return it;
}

template<class T>
typename ListCpp<T>::LIter ListCpp<T>::End()
{
    LIter   it(ListEnd(m_list));
    return it;
}

template<class T>
typename ListCpp<T>::CLIter ListCpp<T>::Begin()const
{
    CLIter   it(ListBegin(m_list));
    return it;
}

template<class T>
typename ListCpp<T>::CLIter ListCpp<T>::End()const
{
    CLIter   it(ListEnd(m_list));
    return it;
}

template<class T>
bool ListCpp<T>::IsEmpty()const
{
    return ListIsEmpty(m_list);
}

template<class T>
typename ListCpp<T>::LIter ListCpp<T>::Insert(LIter _it,T* _data)
{
    LIter   it(ListInsert(m_list,_it.m_iter,_data));
    return  it;
}

template<class T>
typename ListCpp<T>::LIter ListCpp<T>::Insert(CLIter _it,T* _data)
{
    LIter   it(ListInsert(m_list,_it.m_iter,_data));
    return  it;
}

template<class T>
typename ListCpp<T>::LIter ListCpp<T>::Remove(LIter _it)
{
    LIter   it(ListRemove(m_list,_it.m_iter));
    return  it;
}

template<class T>
typename ListCpp<T>::LIter ListCpp<T>::Remove(CLIter _it)
{
    LIter   it(ListRemove(m_list,_it.m_iter));
    return  it;
}


#endif // __LISTCPP__
